﻿Imports Microsoft.IdentityModel.Protocols.WSFederation.Metadata
Imports Microsoft.IdentityModel.Protocols.WSIdentity
Imports System.ServiceModel
Imports System.Security.Cryptography.X509Certificates

Public Class frmMain

    Dim manifestdb As MetadataBase = Nothing
    Dim _manifestEntity As EntityDescriptor = Nothing


    Public ReadOnly Property ManifestEntity As EntityDescriptor
        Get
            Return CType(manifestdb, EntityDescriptor)
        End Get
    End Property






    Private Sub cmdBrowse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdBrowse.Click
        If Me.OpenMetadataFileDialog.ShowDialog = DialogResult.OK Then
            Me.fldFilePath.Text = OpenMetadataFileDialog.FileName
        End If
    End Sub

    Private Sub cmdLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdLoad.Click
        If Not String.IsNullOrEmpty(Me.fldFilePath.Text.Trim) Then
            If IO.File.Exists(Me.fldFilePath.Text.Trim) Then
                ' TODO: Add some error handling code here
                Dim mds As New MetadataSerializer()
                Dim fs As IO.FileStream = IO.File.OpenRead(Me.fldFilePath.Text)
                manifestdb = mds.ReadMetadata(fs)
                fs.Close()
                If manifestdb IsNot Nothing AndAlso TypeOf (manifestdb) Is EntityDescriptor Then
                    LoadEntity(CType(manifestdb, EntityDescriptor))
                Else
                    MsgBox("Error reading manifest file!", MsgBoxStyle.Critical, "Error")
                End If
            Else
                MsgBox("Manifest file doesn't exist!", MsgBoxStyle.Critical, "Error")
            End If
        Else
            MsgBox("You have to select a manifest file!", MsgBoxStyle.Critical, "Error")
        End If
    End Sub

    Private Sub LoadEntity(ByVal myEntity As EntityDescriptor)
        Me.issuerUri_TextBox.Text = myEntity.EntityId.Id
        If myEntity.RoleDescriptors.Count > 0 Then
            If TypeOf (myEntity.RoleDescriptors(0)) Is SecurityTokenServiceDescriptor Then
                With CType(myEntity.RoleDescriptors(0), SecurityTokenServiceDescriptor)
                    Me.serviceName_TextBox.Text = .ServiceDescription
                    Me.ActiveClaims.Clear()
                    For Each claim In .ClaimTypesOffered
                        Me.ActiveClaims.Add(CustomDisplayClaim.FromDisplayClaim(claim))
                    Next
                    Me.EndPointsDataSet.PassiveEndPoints.Rows.Clear()
                    For Each endpoint As EndpointAddress In .PassiveRequestorEndpoints
                        Dim newRow As DataRow = Me.EndPointsDataSet.PassiveEndPoints.NewRow()
                        newRow("Url") = endpoint.Uri.OriginalString
                        Me.EndPointsDataSet.PassiveEndPoints.Rows.Add(newRow)
                    Next
                    Me.EndPointsDataSet.ActiveEndPoints.Rows.Clear()
                    For Each endpoint As EndpointAddress In .SecurityTokenServiceEndpoints
                        Dim newRow As DataRow = Me.EndPointsDataSet.ActiveEndPoints.NewRow()
                        newRow("Url") = endpoint.Uri.OriginalString
                        Me.EndPointsDataSet.ActiveEndPoints.Rows.Add(newRow)
                    Next
                    If .Keys.Count > 0 Then
                        If .Keys.Count > 1 Then
                            MsgBox("Metadata file contains more than one certificate files! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
                        End If
                        If .Keys(0).KeyInfo.Count > 0 Then
                            If TypeOf (.Keys(0).KeyInfo(0)) Is IdentityModel.Tokens.X509RawDataKeyIdentifierClause Then
                                Try
                                    selectedSigningCertificate = New X509Certificate2(CType(.Keys(0).KeyInfo(0), IdentityModel.Tokens.X509RawDataKeyIdentifierClause).GetX509RawData)
                                    LoadInstalledCertificates(selectedSigningCertificate)
                                Catch
                                    MsgBox("Couldn't retrieve the certificate!", MsgBoxStyle.Exclamation, "Warning")
                                End Try
                            End If
                        End If

                    End If
                End With
            Else
                MsgBox("The first role descriptor must be a SecurityTokenServiceDescriptor for an STS!", MsgBoxStyle.Exclamation, "Warning")
            End If
        Else
            MsgBox("No role descriptors are specified in the metadata file!", MsgBoxStyle.Exclamation, "Warning")
        End If

        If myEntity.Contacts.Count > 0 Then
            If myEntity.Contacts.Count > 1 Then
                MsgBox("Metadata file contains more than one contact info! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
            End If
            With myEntity.Contacts(0)
                Contact_CompanyTextBox.Text = .Company
                If .EmailAddresses.Count > 0 Then
                    If .EmailAddresses.Count > 1 Then
                        MsgBox("Metadata file contains more than one email for the contact person! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
                    End If
                    Me.Contact_EmailTextBox.Text = .EmailAddresses(0)
                End If
                Me.Contact_GivenNameTextBox.Text = .GivenName
                Me.Contact_SurnameTextBox.Text = .Surname
                If .TelephoneNumbers.Count > 0 Then
                    If .TelephoneNumbers.Count > 1 Then
                        MsgBox("Metadata file contains more than one telephone number for the contact person! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
                    End If
                    Me.Contact_TelephoneTextBox.Text = .TelephoneNumbers(0)
                End If
                Me.Contact_TypeComboBox.SelectedItem = .Type
            End With

            'Verify that the Organization information is not null
            If myEntity.Organization IsNot Nothing Then
                With myEntity.Organization
                    If .DisplayNames.Count > 0 Then
                        If .DisplayNames.Count > 1 Then
                            MsgBox("Metadata file contains more than one display name for the company! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
                        End If
                        Me.Company_DisplayName.Text = .DisplayNames(0).Name
                    End If
                    If .Names.Count > 0 Then
                        If .Names.Count > 1 Then
                            MsgBox("Metadata file contains more than one name for the company! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
                        End If
                        Me.Company_Name.Text = .Names(0).Name
                    End If
                    If .Urls.Count > 0 Then
                        If .Urls.Count > 1 Then
                            MsgBox("Metadata file contains more than one Url for the company! This information will be lost if you save...", MsgBoxStyle.Exclamation, "Warning")
                        End If
                        Me.Company_URL.Text = .Urls(0).Uri.OriginalString
                    End If
                End With
            End If
        ElseIf myEntity.Contacts.Count = 0 Then
            'REM No Need to load Contact Info
            'MsgBox("Metadata file doesn't contain any contact info!", MsgBoxStyle.Exclamation, "Warning")
        End If
       
    End Sub

    ReadOnly Property ActiveClaims As CustomDisplayClaimCollection
        Get
            Return CType(Me.DisplayClaimCollectionBindingSource.DataSource, CustomDisplayClaimCollection)
        End Get
    End Property

    Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Me.Contact_TypeComboBox.Items.Add(ContactType.Administrative)
        Me.Contact_TypeComboBox.Items.Add(ContactType.Billing)
        Me.Contact_TypeComboBox.Items.Add(ContactType.Other)
        Me.Contact_TypeComboBox.Items.Add(ContactType.Support)
        Me.Contact_TypeComboBox.Items.Add(ContactType.Technical)
        Me.Contact_TypeComboBox.Items.Add(ContactType.Unspecified)
        Me.DisplayClaimCollectionBindingSource.DataSource = New CustomDisplayClaimCollection
    End Sub

    Private Sub cmdAddNewClaim_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdAddNewClaim.Click
        ActiveClaims.Add(New CustomDisplayClaim With {.claimType = "http://"})
    End Sub

    Property selectedSigningCertificate As X509Certificate2

    Private Sub cmdSelectInstalledCertificate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSelectInstalledCertificate.Click
        Dim store As New X509Store(StoreLocation.LocalMachine)
        store.Open(OpenFlags.OpenExistingOnly)
        Dim SelectedCertificates As X509Certificate2Collection = X509Certificate2UI.SelectFromCollection(store.Certificates, "Please select the signing certificate", "The selected certificate will be used to sign the federation metadata document and to identify the STS on the RP.", X509SelectionFlag.SingleSelection)
        If (SelectedCertificates.Count > 0) Then
            AssignSelectedCertificate(SelectedCertificates.Item(0))
        End If
        store.Close()
    End Sub

    Private Sub LoadInstalledCertificates(ByRef cer As X509Certificate2)
        Dim store As New X509Store(StoreLocation.LocalMachine)
        store.Open(OpenFlags.OpenExistingOnly)
        Dim certColl As X509Certificate2Collection = store.Certificates

        'Set the original certificate Thumbprint for display and reference purposes
        SetOriginalCertificateThumbprint(cer)

        'Set the default installed certificate as the current certificate used in signing
        Dim installedCertificate As X509Certificate2 = cer

        'Iterate through the Certificate Store Collection to find the matching installed certificate
        For Each x509 In certColl
            If x509.Subject = cer.Subject Then
                'Set the installed certificate to the X509 Certificate contained in the Certificate Store
                installedCertificate = x509
                'Set the original certificate to the X509 Certificate contained in the Certificate Store
                'so that the Private Key is retained through the Signing operation (since the parameter is passed ByRef)
                cer = x509
            End If
        Next x509

        store.Close()
        AssignSelectedCertificate(installedCertificate)
    End Sub

    Private Sub SetOriginalCertificateThumbprint(ByVal cer As X509Certificate2)
        Me.txtOriginalThumbprint.Text = cer.Thumbprint
    End Sub

    Private Sub AssignSelectedCertificate(ByRef cer As X509Certificate2)
        Me.selectedSigningCertificate = cer
        Me.Certificate_Signing_Subject.Text = Me.selectedSigningCertificate.Subject
        Me.txtThumbprintValue.Text = Me.selectedSigningCertificate.Thumbprint
        Me.chkSignManifest.Enabled = Me.selectedSigningCertificate.HasPrivateKey
        Me.chkSignManifest.Checked = Me.selectedSigningCertificate.HasPrivateKey
    End Sub

    Private Sub cmdSelectCertificateFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSelectCertificateFile.Click
        If My.Forms.frmSelectCertificateFile.ShowDialog = DialogResult.OK Then
            If My.Forms.frmSelectCertificateFile.selectedSigningCertificate IsNot Nothing Then
                AssignSelectedCertificate(My.Forms.frmSelectCertificateFile.selectedSigningCertificate)
            End If
        End If
    End Sub

    Private Sub cmdSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSave.Click
        If Not String.IsNullOrEmpty(Me.fldFilePath.Text.Trim) Then
            Try
                Dim activeEndpoints As New Collections.Specialized.StringCollection
                For Each row As EndPointsDataSet.ActiveEndPointsRow In Me.EndPointsDataSet.ActiveEndPoints.Rows
                    activeEndpoints.Add(row.Url)
                Next
                Dim passiveEndpoints As New Collections.Specialized.StringCollection
                For Each row As EndPointsDataSet.PassiveEndPointsRow In Me.EndPointsDataSet.PassiveEndPoints.Rows
                    passiveEndpoints.Add(row.Url)
                Next

                If Me.ManifestEntity.Contacts.Count = 0 Then
                    Dim generator As New MetadataGenerator(Me.issuerUri_TextBox.Text, Me.serviceName_TextBox.Text, activeEndpoints, passiveEndpoints, ActiveClaims, Me.selectedSigningCertificate, Me.chkSignManifest.Checked)
                    generator.GenerateAsFile(Me.fldFilePath.Text)
                ElseIf Me.ManifestEntity.Contacts.Count > 0 Then
                    Dim contactPerson As New ContactPerson With {.Company = Contact_CompanyTextBox.Text, .GivenName = Contact_GivenNameTextBox.Text, .Surname = Contact_SurnameTextBox.Text, .Type = Contact_TypeComboBox.SelectedItem}
                    contactPerson.EmailAddresses.Add(Me.Contact_EmailTextBox.Text)
                    contactPerson.TelephoneNumbers.Add(Me.Contact_TelephoneTextBox.Text)
                    Dim organization As New Organization
                    organization.DisplayNames.Add(New LocalizedName(Company_DisplayName.Text, Globalization.CultureInfo.InvariantCulture))
                    organization.Names.Add(New LocalizedName(Company_Name.Text, Globalization.CultureInfo.InvariantCulture))
                    organization.Urls.Add(New LocalizedUri(New Uri(Company_URL.Text), Globalization.CultureInfo.InvariantCulture))

                    Dim generator As New MetadataGenerator(contactPerson, organization, Me.issuerUri_TextBox.Text, Me.serviceName_TextBox.Text, activeEndpoints, passiveEndpoints, ActiveClaims, Me.selectedSigningCertificate, Me.chkSignManifest.Checked)
                    generator.GenerateAsFile(Me.fldFilePath.Text)
                End If
            Catch ex As Exception
                'TODO: customize errors
                MsgBox(String.Format("An error occurred saving the file. The message is {0}!", ex.Message), MsgBoxStyle.Critical, "Error")
            End Try
            MsgBox("Save completed successfully!", MsgBoxStyle.Information, "Save completed")
        Else
            MsgBox("You must specify the manifest file path!", MsgBoxStyle.Critical, "Error")
        End If
    End Sub

    Private Sub txtCopiedThumbprint_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtCopiedThumbprint.TextChanged
        Dim copiedThumbPrint As String

        copiedThumbPrint = txtCopiedThumbprint.Text

        Dim thumbprintChars As String() = copiedThumbPrint.Split(New Char() {" "})
        Dim parsedThumbPrint As String = String.Concat(thumbprintChars)

        txtParsedThumbprint.Text = parsedThumbPrint.ToUpper()

    End Sub

    Private Sub cmdDisplayClaimTypes_Click(sender As System.Object, e As System.EventArgs) Handles cmdDisplayClaimTypes.Click
        If frmDisplayClaimTypes.ShowDialog = DialogResult.OK Then
            'Me.fldFilePath.Text = OpenMetadataFileDialog.FileName
        End If
    End Sub
End Class
